//
// Created by lvyer on 2021/11/19.
//

#include <TextureRenderer.h>

TextureRenderer::TextureRenderer() {

}

TextureRenderer::~TextureRenderer() {

}

//初始化着色器小程序 并编译着色器代码 并链接
void TextureRenderer::init() {
    char vShaderStr[] =
            "#version 300 es                      \n"
            "layout (location = 0) in vec3 aPos;      \n"
            "layout (location = 1) in vec3 aColor;\n"
            "layout (location = 2) in vec2 aTexCoord; \n"
            "out vec3 ourColor;  \n"
            "out vec2 texCoord;  \n"
            "void main()\n"
            "{\n"
            "    gl_Position = vec4(aPos, 1.0);\n"
            "    ourColor = aColor;\n"
            "    texCoord = vec2(aTexCoord.x, aTexCoord.y);\n"
            "}";

    char fShaderStr[] =
            "#version 300 es  \n"
            "precision mediump float; \n"
            "out vec4 FragColor; \n"
            "in vec3 ourColor; \n"
            "in vec2 texCoord;  \n"
            "\n"
            "uniform sampler2D texture1; \n"
            "void main() \n"
            "{\n"
            "    FragColor = texture(texture1, texCoord);\n"
            "}";

    m_ProgramObj = GLTools::createProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);

    // 通过id通知GPU 我们要使用这个着色器程序了
    glUseProgram(m_ProgramObj);

    float vertices[] = {
            // positions          // colors           // texture coords
            0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top right
            0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // bottom right
            -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // bottom left
            -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f  // top left
    };
    unsigned int indices[] = {
            0, 1, 3, // first triangle
            1, 2, 3  // second triangle
    };

    //初始化创建 VBO  VAO  EBO 对象
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    //为当前使用的着色器程序绑定VAO 顶点缓冲数组对象
    glBindVertexArray(VAO);
    //为当前绑定 顶点缓冲对象
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //为当前已绑定的缓冲对象填充数据
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    //创建索引缓冲对象
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    //填充索引数据和规则
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // 为顶点着色器的 0号变量赋值
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float),
                          (void *) (3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float),
                          (void *) (6 * sizeof(float)));
    glEnableVertexAttribArray(2);


    // texture 1
    // ---------
    glGenTextures(1, &texture);
    // 在绑定纹理之前先激活纹理单元 由于第一个纹理单元是默认激活的 所以只有
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    // set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                    GL_CLAMP_TO_EDGE);    // set texture wrapping to GL_REPEAT (default wrapping method)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    LOGD("TextureRenderer&texture texture=%d", texture);
    //最后一个参数 表示对应纹理第几层 这个层级是从0~16，后面会有激活第几层纹理的时候使用的是 GL_TEXTURE0~16层 与这里的层级对应，但是不相等
    glUniform1i(glGetUniformLocation(m_ProgramObj, "texture1"), 0);
}

void TextureRenderer::draw() {
    LOGD("TextureRenderer draw: width=%d,height=%d", width, height);

    if (m_ProgramObj == 0)
        return;
    //清除上次渲染内容
    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(1.0, 1.0, 1.0, 1.0);

    LOGD("TextureRenderer draw m_ProgramObj=%d", m_ProgramObj);

    // bind textures on corresponding texture units
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

void TextureRenderer::onSurfaceChanged(int width, int height) {
    this->width = width;
    this->height = height;
    glViewport(0, 0, width, height);
}

void TextureRenderer::setImageData(int format, int width, int height, uint8_t *data) {
    if (texture != -1) {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    }

}
